/**
 * Copyright (C) 2014-2019 by Wen Yu.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * <p>
 * Any modifications to this file must keep this entire header intact.
 * <p>
 * Change History - most recent changes go on top of previous changes
 * <p>
 * TextualChunk.java
 * <p>
 * Who   Date       Description
 * ====  =========  =================================================
 * WY    04Nov2015  Added chunk type check
 * WY    09Jul2015  Rewrote to work with multiple textual chunks
 * WY    05Jul2015  Added write support
 * WY    05Jul2015  Initial creation
 */

package com.symaster.common.pixy.meta.png;

import com.symaster.common.pixy.image.png.Chunk;
import com.symaster.common.pixy.image.png.ChunkType;
import com.symaster.common.pixy.image.png.TextReader;
import com.symaster.common.pixy.meta.Metadata;
import com.symaster.common.pixy.meta.MetadataEntry;
import com.symaster.common.pixy.meta.MetadataType;

import java.io.IOException;
import java.util.*;

public class TextualChunks extends Metadata {
    /* This queue is used to keep track of the unread chunks
     * After it's being read, all of it's elements will be moved
     * to chunks list
     */
    private final Queue<Chunk> queue;
    // We keep chunks and keyValMap in sync
    private final List<Chunk> chunks;
    private final Map<String, String> keyValMap;

    public TextualChunks() {
        super(MetadataType.PNG_TEXTUAL);
        this.queue = new LinkedList<Chunk>();
        this.chunks = new ArrayList<Chunk>();
        this.keyValMap = new HashMap<String, String>();
    }

    public TextualChunks(Collection<Chunk> chunks) {
        super(MetadataType.PNG_TEXTUAL);
        validateChunks(chunks);
        this.queue = new LinkedList<Chunk>(chunks);
        this.chunks = new ArrayList<Chunk>();
        this.keyValMap = new HashMap<String, String>();
    }

    private static void validateChunks(Collection<Chunk> chunks) {
        for (Chunk chunk : chunks)
            validateChunkType(chunk.getChunkType());
    }

    private static void validateChunkType(ChunkType chunkType) {
        if ((chunkType != ChunkType.TEXT) && (chunkType != ChunkType.ITXT)
                && (chunkType != ChunkType.ZTXT))
            throw new IllegalArgumentException("Expect Textual chunk!");
    }

    public List<Chunk> getChunks() {
        ArrayList<Chunk> chunkList = new ArrayList<Chunk>(chunks);
        chunkList.addAll(queue);
        return chunkList;
    }

    public Map<String, String> getKeyValMap() {
        ensureDataRead();
        return Collections.unmodifiableMap(keyValMap);
    }

    public void addChunk(Chunk chunk) {
        validateChunkType(chunk.getChunkType());
        queue.offer(chunk);
    }

    public Iterator<MetadataEntry> iterator() {
        ensureDataRead();
        List<MetadataEntry> entries = new ArrayList<MetadataEntry>();

        for (Map.Entry<String, String> entry : keyValMap.entrySet()) {
            entries.add(new MetadataEntry(entry.getKey(), entry.getValue()));
        }

        return Collections.unmodifiableCollection(entries).iterator();
    }

    public void read() throws IOException {
        if (queue.size() > 0) {
            TextReader reader = new TextReader();
            for (Chunk chunk : queue) {
                reader.setInput(chunk);
                String key = reader.getKeyword();
                String text = reader.getText();
                String oldText = keyValMap.get(key);
                keyValMap.put(key, (oldText == null) ? text : oldText + "; " + text);
                chunks.add(chunk);
            }
            queue.clear();
        }
    }
}
